package org.jeecg.modules.inOrder.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.DateUtils;
import org.jeecg.constant.WarehouseConstant;
import org.jeecg.modules.basicSkuInfo.entity.BasicSkuInfo;
import org.jeecg.modules.basicSkuInfo.service.IBasicSkuInfoService;
import org.jeecg.modules.inOrder.entity.InOrder;
import org.jeecg.modules.inOrder.entity.InOrderDetail;
import org.jeecg.modules.inOrder.mapper.InOrderDetailMapper;
import org.jeecg.modules.inOrder.mapper.InOrderMapper;
import org.jeecg.modules.inOrder.service.IInOrderDetailService;
import org.jeecg.modules.inOrder.service.IInOrderService;
import org.jeecg.modules.inOrderRules.entity.InOrderRules;
import org.jeecg.modules.inOrderTaskMain.entity.InOrderTaskDetail;
import org.jeecg.modules.inOrderTaskMain.entity.InOrderTaskMain;
import org.jeecg.modules.inOrderTaskMain.mapper.InOrderTaskDetailMapper;
import org.jeecg.modules.inOrderTaskMain.mapper.InOrderTaskMainMapper;
import org.jeecg.modules.inOrderTaskMain.service.IInOrderTaskDetailService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 入库单主表
 * @Author: jeecg-boot
 * @Date: 2023-11-09
 * @Version: V1.0
 */
@Service
public class InOrderServiceImpl extends ServiceImpl<InOrderMapper, InOrder> implements IInOrderService {

    @Resource
    private IBasicSkuInfoService basicSkuInfoService;
    @Resource
    private InOrderMapper inOrderMapper;
    @Resource
    private InOrderDetailMapper inOrderDetailMapper;
    @Resource
    private InOrderTaskMainMapper inOrderTaskMainMapper;
    @Resource
    private InOrderTaskDetailMapper inOrderTaskDetailMapper;
    @Resource
    private IInOrderTaskDetailService inOrderTaskDetailService;
    @Resource
    private IInOrderDetailService iInOrderDetailService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveWarehousingEntry(InOrder inOrder, List<InOrderDetail> inOrderDetailList) {
        // 生成订单号
        if (StringUtils.isBlank(inOrder.getInOrderCode())) {
            inOrder.setInOrderCode(DateUtils.getToday() + "-" + System.currentTimeMillis());
        }

        Integer skuType = inOrder.getGoodsType();
        // 校验输入的品番是否存在
        for (InOrderDetail inOrderDetail : inOrderDetailList) {
            QueryWrapper<BasicSkuInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("sku_type", skuType);
            queryWrapper.eq("sku_code", inOrderDetail.getSkuCode());
            int count = basicSkuInfoService.count(queryWrapper);
            Assert.isFalse(count == 0, "想要入库的品番编码【%s】不存在！", inOrderDetail.getSkuCode());
//            Assert.isFalse(count > 1, "想要入库的品番编码【%s】已重复！请正确维护品番信息后重新入库！", inOrderDetail.getSkuCode());
        }
        // 保存入库单
        if (null == inOrder.getId()) {
            this.saveMain(inOrder, inOrderDetailList);
        } else {
            this.updateMain(inOrder, inOrderDetailList);
        }
    }

    /**
     * 保存入库单
     *
     * @param inOrder           入库单主表
     * @param inOrderDetailList 入库单子表
     */
    @Override
    public void saveMain(InOrder inOrder, List<InOrderDetail> inOrderDetailList) {
        inOrder.setStatus(WarehouseConstant.EnterWarehouseEnum.CREATE_END.getCode());
        inOrderMapper.insert(inOrder);
        if (CollectionUtils.isNotEmpty(inOrderDetailList)) {
            for (InOrderDetail inOrderDetail : inOrderDetailList) {
                inOrderDetail.setInOrderId(inOrder.getId());
                inOrderDetail.setStatus(CommonConstant.STATUS_1);
            }
            iInOrderDetailService.saveBatch(inOrderDetailList);
        }
    }

    /**
     * 更新入库单
     *
     * @param inOrder           入库单主表
     * @param inOrderDetailList 入库单子表
     */
    @Override
    public void updateMain(InOrder inOrder, List<InOrderDetail> inOrderDetailList) {
        inOrderMapper.updateById(inOrder);
        inOrderDetailMapper.deleteByMainId(inOrder.getId());
        if (CollectionUtils.isNotEmpty(inOrderDetailList)) {
            for (InOrderDetail inOrderDetail : inOrderDetailList) {
                inOrderDetail.setInOrderId(inOrder.getId());
            }
            iInOrderDetailService.saveBatch(inOrderDetailList);
        }
    }

    /**
     * 发布入库单
     *
     * @param id 入库单id
     */
    @Override
    public void releaseWarehousingEntry(String id) {
        InOrder inOrder = inOrderMapper.selectById(id);
        Assert.notNull(inOrder, "入库单数据异常，请联系管理员！");
        Assert.isFalse(WarehouseConstant.EnterWarehouseEnum.RELEASE_END.getCode().equals(inOrder.getStatus()), "请勿重复发布！");
        Assert.isFalse(WarehouseConstant.EnterWarehouseEnum.EXECUTE_END.getCode().equals(inOrder.getStatus()), "入库单已入库完成，无需发布！");
        Assert.isFalse(WarehouseConstant.EnterWarehouseEnum.FORCE_END.getCode().equals(inOrder.getStatus()), "入库单已入库完成，无需发布！");
        Assert.isFalse(WarehouseConstant.EnterWarehouseEnum.DELETE.getCode().equals(inOrder.getStatus()), "入库单已被删除，无法发布！");

        // 更新入库单状态
        inOrder.setReleaseTime(new Date());
        inOrder.setStatus(WarehouseConstant.EnterWarehouseEnum.RELEASE_END.getCode());
        inOrderMapper.updateById(inOrder);

        // 生成入库任务
        this.createEnterTask(inOrder);
    }

    /**
     * 生成入库任务
     *
     * @param inOrder 入库单
     */
    private void createEnterTask(InOrder inOrder) {
        List<InOrderDetail> inOrderDetailList = inOrderDetailMapper.selectList(new QueryWrapper<InOrderDetail>().eq("in_order_id", inOrder.getId()));
        Assert.notEmpty(inOrderDetailList, "入库单数据异常，请联系管理员！");

        inOrder.setStatus(WarehouseConstant.EnterWarehouseEnum.RELEASE_END.getCode());

        if (Objects.equals(inOrder.getGoodsType(), WarehouseConstant.SkuTypeEnum.PT.getCode())) {
            // PT品只需理货员领取任务
            this.createTask(WarehouseConstant.EnterWarehouseTaskStaffEnum.TALLY.getCode(), inOrder, inOrderDetailList);
            inOrder.setExecuteStaff(WarehouseConstant.EnterWarehouseTaskStaffEnum.TALLY.getCode());
        } else if (Objects.equals(inOrder.getGoodsType(), WarehouseConstant.SkuTypeEnum.SF.getCode())) {
            // AGV区市贩品品番列表
            List<BasicSkuInfo> agvSfSkuDetailList = basicSkuInfoService.list(new QueryWrapper<BasicSkuInfo>()
                    .eq("sku_type", WarehouseConstant.SkuTypeEnum.SF.getCode())
                    .eq("warehouse_code", WarehouseConstant.WarehouseTypeEnum.AGV.getCode()));

            if (CollectionUtils.isEmpty(agvSfSkuDetailList)) {
                // AGV区市贩品品番列表为空 全部入到高位库
                this.createTask(WarehouseConstant.EnterWarehouseTaskStaffEnum.DRIVER.getCode(), inOrder, inOrderDetailList);
                inOrder.setExecuteStaff(WarehouseConstant.EnterWarehouseTaskStaffEnum.DRIVER.getCode());
            } else {
                // 过滤出需要入库至AGV区域的市贩品品番编码
                List<String> agvSfSkuCodeList = agvSfSkuDetailList.stream().map(BasicSkuInfo::getSkuCode).collect(Collectors.toList());
                // 分组为AGV区入库单详情与高位库区入库单详情
                Map<Boolean, List<InOrderDetail>> partitionedMap = inOrderDetailList.stream()
                        .collect(Collectors.partitioningBy(detail -> agvSfSkuCodeList.contains(detail.getSkuCode())));
                // 获取AGV区入库单详情
                List<InOrderDetail> agvInOrderDetailList = partitionedMap.get(true);
                this.createTask(WarehouseConstant.EnterWarehouseTaskStaffEnum.TALLY.getCode(), inOrder, agvInOrderDetailList);
                // 获取高位库区入库单详情
                List<InOrderDetail> gwkInOrderDetailList = partitionedMap.get(false);
                this.createTask(WarehouseConstant.EnterWarehouseTaskStaffEnum.DRIVER.getCode(), inOrder, gwkInOrderDetailList);

                if (CollectionUtils.isNotEmpty(agvInOrderDetailList) && CollectionUtils.isNotEmpty(gwkInOrderDetailList)) {
                    // 都不为空，需要理货员和叉车司机执行任务
                    inOrder.setExecuteStaff(WarehouseConstant.EnterWarehouseTaskStaffEnum.TALLY_DRIVER.getCode());
                } else if (CollectionUtils.isEmpty(agvInOrderDetailList) && CollectionUtils.isNotEmpty(gwkInOrderDetailList)) {
                    // AGV入库单详情为空，需要叉车司机执行任务
                    inOrder.setExecuteStaff(WarehouseConstant.EnterWarehouseTaskStaffEnum.DRIVER.getCode());
                } else if (CollectionUtils.isNotEmpty(agvInOrderDetailList) && CollectionUtils.isEmpty(gwkInOrderDetailList)) {
                    // 高位库入库单详情为空，需要理货员执行任务
                    inOrder.setExecuteStaff(WarehouseConstant.EnterWarehouseTaskStaffEnum.TALLY.getCode());
                }
            }

        }

        inOrderMapper.updateById(inOrder);
    }

    /**
     * 创建理货员或叉车司机的任务
     *
     * @param executeStaff      任务执行人员
     * @param inOrder           入库单
     * @param inOrderDetailList 入库单详情
     */
    public void createTask(String executeStaff, InOrder inOrder, List<InOrderDetail> inOrderDetailList) {
        if (CollectionUtils.isEmpty(inOrderDetailList)) {
            return;
        }

        InOrderTaskMain inOrderTaskMain = new InOrderTaskMain();
        inOrderTaskMain.setInOrderId(inOrder.getId());
        inOrderTaskMain.setExecuteStaff(executeStaff);
        inOrderTaskMain.setStatus(WarehouseConstant.EnterWarehouseEnum.RELEASE_END.getCode());
        inOrderTaskMainMapper.insert(inOrderTaskMain);

        List<InOrderTaskDetail> inOrderTaskDetailList = inOrderDetailList.stream().map(data -> {
            InOrderTaskDetail inOrderTaskDetail = new InOrderTaskDetail();
            BeanUtils.copyProperties(data, inOrderTaskDetail);
            inOrderTaskDetail.setInOrderTaskId(inOrderTaskMain.getId());
            inOrderTaskDetail.setStatus(WarehouseConstant.EnterWarehouseDetailEnum.ENTER_NOT.getCode());
            return inOrderTaskDetail;
        }).collect(Collectors.toList());
        inOrderTaskDetailService.saveBatch(inOrderTaskDetailList);
    }

    // 根据策略查询符合货架
    @Override
    public List<String> queryShelf(InOrderRules inOrderRules) {
        List<String> emptyShelf = inOrderMapper.getEmptyShelf();//空货架
        if (emptyShelf.isEmpty()) {
            emptyShelf.add("null");
        }
        List<String> emptyCompartment = inOrderMapper.getEmptyCompartment(inOrderRules);//非空货架空货位
        if (emptyCompartment.isEmpty()) {
            emptyCompartment.add("null");
        }
        List<String> noEmpty = inOrderMapper.getNoEmpty(inOrderRules);//非空货架非空货位
        if (noEmpty.isEmpty()) {
            noEmpty.add("null");
        }
        List<String> list = new ArrayList<>();//按货架优先级整合数据
        switch (inOrderRules.getShelfPriority()) {
            case 0:
                list.addAll(emptyShelf);
                list.addAll(emptyCompartment);
                list.addAll(noEmpty);
                break;
            case 1:
                list.addAll(emptyShelf);
                list.addAll(noEmpty);
                list.addAll(emptyCompartment);
                break;
            case 2:
                list.addAll(noEmpty);
                list.addAll(emptyCompartment);
                list.addAll(emptyShelf);
                break;
            case 3:
                list.addAll(noEmpty);
                list.addAll(emptyShelf);
                list.addAll(emptyCompartment);
                break;
            case 4:
                list.addAll(emptyCompartment);
                list.addAll(noEmpty);
                list.addAll(emptyShelf);
                break;
            case 5:
                list.addAll(emptyCompartment);
                list.addAll(emptyShelf);
                list.addAll(noEmpty);
                break;
            default:
                break;
        }
        list.removeAll(Collections.singletonList("null"));
        return list;
    }

    @Override
    @Transactional
    public void delMain(String id) {
        InOrder inOrder = inOrderMapper.selectById(id);
        Assert.notNull(inOrder, "不存在的入库单无法进行删除！");
        Assert.isTrue(Arrays.asList(WarehouseConstant.EnterWarehouseEnum.CREATE_END.getCode(), WarehouseConstant.EnterWarehouseEnum.RELEASE_END.getCode()).contains(inOrder.getStatus()), "入库单只有在领取任务前才可删除，当前状态不支持删除！");

        // 更新入库单主子表有效标志
        inOrder.setStatus(WarehouseConstant.EnterWarehouseEnum.DELETE.getCode());
        inOrderMapper.updateById(inOrder);

        inOrderDetailMapper.update(new InOrderDetail().setStatus(WarehouseConstant.EnterWarehouseDetailEnum.DELETE.getCode()),
                new LambdaQueryWrapper<InOrderDetail>().eq(InOrderDetail::getInOrderId, id));

        // 如果入库单已发布了，需要删除对应的任务
        if (WarehouseConstant.EnterWarehouseEnum.RELEASE_END.getCode().equals(inOrder.getStatus())) {
            List<InOrderTaskMain> inOrderTaskMainList = inOrderTaskMainMapper.selectList(new LambdaQueryWrapper<InOrderTaskMain>().eq(InOrderTaskMain::getInOrderId, id));
            if (CollectionUtils.isNotEmpty(inOrderTaskMainList)) {
                for (InOrderTaskMain inOrderTaskMain : inOrderTaskMainList) {
                    inOrderTaskMain.setStatus(WarehouseConstant.EnterWarehouseEnum.DELETE.getCode());
                    inOrderTaskMainMapper.updateById(inOrderTaskMain);
                }

                inOrderTaskDetailMapper.update(new InOrderTaskDetail().setStatus(WarehouseConstant.EnterWarehouseDetailEnum.DELETE.getCode()),
                        new LambdaQueryWrapper<InOrderTaskDetail>().in(InOrderTaskDetail::getInOrderTaskId, inOrderTaskMainList.stream().map(InOrderTaskMain::getId).collect(Collectors.toList())));
            }
        }
    }

    @Override
    @Transactional
    public void delBatchMain(Collection<? extends Serializable> idList) {
        List<InOrder> inOrderList = inOrderMapper.selectList(new QueryWrapper<InOrder>()
                .in("id", idList)
                .in("status", Arrays.asList(WarehouseConstant.EnterWarehouseEnum.CREATE_END.getCode(), WarehouseConstant.EnterWarehouseEnum.RELEASE_END.getCode())));
        Assert.isTrue(idList.size() == inOrderList.size(), "入库单只有在领取任务前才可删除，当前状态不支持删除！");

        // 删除每个入库单
        if (CollectionUtils.isNotEmpty(inOrderList)) {
            for (InOrder inOrder : inOrderList) {
                this.delMain(inOrder.getId());
            }
        }
    }

}
